package com.dream.utils.resource.i18n;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.collections.MapUtils;

import com.dream.utils.io.FileIOUtils;
import com.dream.utils.log.DreamLogUtils;
import com.dream.utils.system.cfg.SystemConfigUtils;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * STMS 2012
 * 
 * @author Evan
 * @date 2012-09-15
 * 
 */
public class MessageResourceUtils {

	private static  Map<Locale, Map<String,Properties>> messageMap= Maps.newHashMap();
	
	private static  Map<String,Properties> defaultProperties = null;
	
	private static Map<String,Set<String>> fileNameMap = Maps.newHashMap();
	
	private static String MESSAGE_NAME = "{0}messages{1}.properties";
	
	private static final MessageResourceUtils INSTANCE = new MessageResourceUtils();
	
	/**
	 * 
	 * @return
	 */
	public static MessageResourceUtils getInstance() {

		return INSTANCE;
	}
	
	private MessageResourceUtils() {
		
		load();
	}
	
	private synchronized void  load(){
		
		List<Object> locals = SystemConfigUtils.instance().getList("i18n.local.item");
		List<Object> files = SystemConfigUtils.instance().getList("i18n.files.item");
		if(locals == null || files == null){
			DreamLogUtils.error(MessageResourceUtils.class, "load", "the supported local not defined", null);
			return;
		}
		for(Object local : locals){
			
			String tL = (String)local;
			Set<String> fSet = Sets.newHashSet();
			fileNameMap.put((String)local,fSet);
			
			for(Object file : files){
				
				String tF = (String)file;
				String tFile = MESSAGE_NAME.replace("{0}", tF);
				
				if(!"".equals(tL)){
					tL =  "_" + tL;
				}
				tFile = tFile.replace("{1}", tL);
				fSet.add(tFile);
			}
			
		}
		
		
		InputStream is=null;
		try {
			
			//get default properties
			defaultProperties = Maps.newHashMap();
			if(fileNameMap.containsKey("")){
				for(String str : fileNameMap.get("")){
					is=MessageResourceUtils.class.getClassLoader().getResourceAsStream(str);
					if(is!=null){
						Properties p = new Properties();
						p.load(is);
						defaultProperties.put(str,p);
						FileIOUtils.close(is);
						is = null;
					}
				}
			}
			
			//get the properties by language
			for(Locale locale :  Locale.getAvailableLocales()){
				
				if(fileNameMap.containsKey(locale.getLanguage())){
					
					Map<String,Properties> map = messageMap.get(locale);
					if(map == null){
						map = Maps.newHashMap();
						messageMap.put(locale, map);
					}
					
					for(String file : fileNameMap.get(locale.getLanguage())){
						is=MessageResourceUtils.class.getClassLoader().getResourceAsStream(file);
						if(is!=null){
							Properties porperty = new Properties();
							porperty.load(is);
							map.put(file, porperty);
							FileIOUtils.close(is);
							is = null;
						}
					}
				}
			}
			

		} catch (IOException e) {
			DreamLogUtils.error(MessageResourceUtils.class, "load", "", e);
			throw new RuntimeException(e);
		}finally{
			FileIOUtils.close(is);
		}
	}

	/**
	 * get default language message
	 * @param key
	 * @return
	 */
	public String getMessage(String key) {
		
		return getDefMessage(key,defaultProperties);
		
	}
	

	/**
	 * get default language message
	 * get message by exact message file name
	 * @param key
	 * @param file
	 * @return
	 */
	public String getMessage(String key,String file) {
		
		return getMessageByFile(key,file,defaultProperties);
	}
	
	private String getDefMessage(String key , Map<String,Properties> map){
		String result = null;
		for(Properties p : map.values()){
			if(p.containsKey(key)){
				result =  (String)p.get(key);
				break;
			}
		}
		return result;
	}
	
	private String getMessageByFile(String key,String file, Map<String,Properties> map){
		
		String result = null;
		if(map.containsKey(file)){
			Properties p = map.get(file);
			if(p != null && p.contains(key)){
				result =  (String)p.get(key);
			}
		}
		
		if(result == null){
			result = getMessage(key);
		}
		
		return result;
	}
	
	/**
	 * get message by language
	 * @param locale
	 * @param key
	 * @return
	 */
	public String getMessage(Locale locale,String key){
		
		Map<String,Properties> map= messageMap.get(locale);
		
		if(MapUtils.isEmpty(map)){
			return getMessage(key);
		}
		
		return getDefMessage(key,map);
		
	}

	/**
	 * get message by language
	 * @param locale
	 * @param key
	 * @return
	 */
	public String getMessage(Locale locale,String key,String file){
		
		Map<String,Properties> map= messageMap.get(locale);
		
		if(MapUtils.isEmpty(map)){
			return getMessage(key);
		}
		
		return getMessageByFile(key,file,map);
		
	}
	
	/**
	 * 
	 */
	public void reflush(){
		
		this.load();
	}

}
